#include "rout_wfq.h"

int head1;
int head2;
int tail1;
int tail2;
int sendrate = 8;
int debugmode = 0;
int debugmode2 = 0;
int flagQ1 = 1;
//int flag2 = 1;
int flagQ2 = 1;
//int flag4 = 1;
long timeArr1[BSIZEINF];
long timeArr2[BSIZEINF];
double finishTime1[BSIZEINF];
double finishTime2[BSIZEINF];
double globalVirtualTime;

FILE *inf, *outf;

int main(int argc, char *argv[]) {
	int iret1, iret2;
	char** buffer1;
	char** buffer2;
	//
	int bufseq[BSIZEINF];
	int rec_sock1 = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
	int rec_sock2 = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
	int send_sock1 = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
	int send_sock2 = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
	int i;
	pthread_t rece, send;
	//globalVirtualTime[0] = 1;
	//globalVirtualTime[1] = 1;
	globalVirtualTime = 1;
	finishTime1[BSIZEINF] = 0.0;//initial finishtime
	finishTime2[BSIZEINF] = 0.0;//initial finishtime

	struct sockaddr_in rec_sa1;
	struct sockaddr_in rec_sa2;
	struct sockaddr_in send_sa1;
	struct sockaddr_in send_sa2;

	RECEIVERSTRUCT* rec_input;
	RECEIVERSTRUCT* send_input;

	//inf = fopen("input_time_wfq.txt", "w");
	outf = fopen("output_time_wfq.txt", "w");



	head1 = 0;
	head2 = 0;
	tail1 = 0;
	tail2 = 0;

	rec_input = (RECEIVERSTRUCT*) malloc(sizeof(RECEIVERSTRUCT));
	send_input = (RECEIVERSTRUCT*) malloc(sizeof(RECEIVERSTRUCT));

	buffer1 = (char**) malloc(BSIZEINF * sizeof(char*));
	buffer2 = (char**) malloc(BSIZEINF * sizeof(char*));
	for (i = 0; i < BSIZEINF; i++)
		buffer1[i] = (char*) malloc(FSIZE * sizeof(char));
	for (i = 0; i < BSIZEINF; i++)
		buffer2[i] = (char*) malloc(FSIZE * sizeof(char));

	memset(&rec_sa1, 0, sizeof(rec_sa1));
	rec_sa1.sin_family = AF_INET;
	rec_sa1.sin_addr.s_addr = INADDR_ANY;
	rec_sa1.sin_port = htons(RECPORT1);

	memset(&rec_sa2, 0, sizeof(rec_sa2));
	rec_sa2.sin_family = AF_INET;
	rec_sa2.sin_addr.s_addr = INADDR_ANY;
	rec_sa2.sin_port = htons(RECPORT2);

	memset(&send_sa1, 0, sizeof(send_sa1));
	send_sa1.sin_family = AF_INET;
	send_sa1.sin_addr.s_addr = INADDR_ANY;
	send_sa1.sin_port = htons(SENDPORT1);

	memset(&send_sa2, 0, sizeof(send_sa2));
	send_sa2.sin_family = AF_INET;
	send_sa2.sin_addr.s_addr = INADDR_ANY;
	//inet_pton(AF_INET, "10.10.1.12", &(send_sa.sin_addr));
	send_sa2.sin_port = htons(SENDPORT2);

	if (-1 == bind(rec_sock1, (struct sockaddr *) &rec_sa1,
			sizeof(struct sockaddr))) {
		perror("error bind failed in router");
		close(rec_sock1);
		exit(EXIT_FAILURE);
	}

	if (-1 == bind(rec_sock2, (struct sockaddr *) &rec_sa2,
			sizeof(struct sockaddr))) {
		perror("error bind failed in router");
		close(rec_sock2);
		exit(EXIT_FAILURE);
	}

	rec_input->socket1 = rec_sock1;
	rec_input->socket2 = rec_sock2;
	rec_input->saddress1 = &rec_sa1;
	rec_input->saddress2 = &rec_sa2;
	rec_input->mainbuffer1 = buffer1;
	rec_input->mainbuffer2 = buffer2;

	send_input->socket1 = send_sock1;
	send_input->saddress1 = &send_sa1;
	send_input->socket2 = send_sock2;
	send_input->saddress2 = &send_sa2;
	send_input->mainbuffer1 = buffer1;
	send_input->mainbuffer2 = buffer2;

	sendrate = atoi(argv[1]);	//sending rate of router

	iret1 = pthread_create(&rece, NULL, receiver, (void*) rec_input);
	//sleep (4);
	iret2 = pthread_create(&send, NULL, sender, (void*) send_input);

	pthread_join(rece, NULL);
	pthread_join(send, NULL);

	close(rec_sock1);
	close(rec_sock2);

	return 0;
}
void delay(int rate) {
	float rateF, delaynsec;
	int delaysec;
	struct timespec tmReq = { 0 }, tmRem = { 0 };
	rateF = (float) rate;
	delaysec = (int) 1 / rateF;
	tmReq.tv_sec = delaysec;
	delaynsec = (float) 1 / rate - delaysec;
	tmReq.tv_nsec = delaynsec * 1000000000L;
	//	printf("in delay1 time %f \n", delaynsec);
	nanosleep(&tmReq, &tmRem);
}

long timestamp() {
	time_t ltime;
	struct timeval ts;
	long timeinms;
	ltime = time(NULL);
	gettimeofday(&ts, NULL);
	timeinms = ts.tv_sec * 1000000 + ts.tv_usec;
	//printf("Here is the time in timeinms: %ld\n", timeinms);
	return timeinms;
}

int msleep(unsigned long milisec) {
	struct timespec req = { 0 };
	time_t sec = (int) (milisec / 1000);
	milisec = milisec - (sec * 1000);
	req.tv_sec = sec;
	req.tv_nsec = milisec * 1000000L;
	while (nanosleep(&req, &req) == -1)
		continue;
	return 1;
}

void *sender(void *input) {
	RECEIVERSTRUCT* inputstruct;
	char buffer[FSIZE];//changed to tokenmax
	//	size_t recsize, fromlen;
	int sock1, sock2;
	int buffer_length, bytes_sent;
	char** mainbuffer1;
	char** mainbuffer2;
	int who;
	int pcount = 0;
	//	int senderCounter = 0;
	//	int rec1 = 0, rec2 = 0;
	//	long queueDelay = 0;
	//pthread_mutex_t* lock;
	struct sockaddr_in sa1;
	struct sockaddr_in sa2;
	inputstruct = (RECEIVERSTRUCT*) input;
	sock1 = inputstruct->socket1;
	sock2 = inputstruct->socket2;

	sa1 = *(inputstruct->saddress1);
	sa2 = *(inputstruct->saddress2);
	mainbuffer1 = inputstruct->mainbuffer1;
	mainbuffer2 = inputstruct->mainbuffer2;
	//lock = inputstruct->mp;

	buffer_length = FSIZE;

	while (1) {
		delay(sendrate);

		if (flagQ1 == 1 && tail1 == head1) { //queue1 is empty
			if (flagQ2 == 1 && tail2 == head2) //queue2 is empty
				continue;
			else {//there is data in queue2, sending data of queue2
				strcpy(buffer, mainbuffer2[tail2]);
				bytes_sent = sendto(sock2, buffer, buffer_length, 0,
						(struct sockaddr*) &sa2, sizeof(struct sockaddr_in));
				tail2 = (tail2 + 1) % BSIZEINF;
				flagQ2 = 1;
				who = 2;
			}
		} else {//there is data in queue1
			if (flagQ2 == 1 && tail2 == head2) {//queue2 is empty
				//sending data of queue1
				strcpy(buffer, mainbuffer1[tail1]);
				bytes_sent = sendto(sock1, buffer, buffer_length, 0,
						(struct sockaddr*) &sa1, sizeof(struct sockaddr_in));
				tail1 = (tail1 + 1) % BSIZEINF;
				flagQ1 = 1;
				who = 1;
			} else { //there is data in queue also!!!!!!!!!
				if (debugmode)
					printf("FT1: %f, FT2: %f\n", finishTime1[tail1],
							finishTime2[tail2]);

				if (finishTime2[tail2] < finishTime1[tail1]) {
					//sending data of queue2
					strcpy(buffer, mainbuffer2[tail2]);
					bytes_sent
							= sendto(sock2, buffer, buffer_length, 0,
									(struct sockaddr*) &sa2,
									sizeof(struct sockaddr_in));
					tail2 = (tail2 + 1) % BSIZEINF;
					flagQ2 = 1;
					who = 2;
				} else {
					//sending data of queue1
					strcpy(buffer, mainbuffer1[tail1]);
					bytes_sent
							= sendto(sock1, buffer, buffer_length, 0,
									(struct sockaddr*) &sa1,
									sizeof(struct sockaddr_in));
					tail1 = (tail1 + 1) % BSIZEINF;
					flagQ1 = 1;
					who = 1;
				}

			}
		}
		pcount++;
		fprintf(outf, "%d\t%ld\t%d\n", who, timestamp(),getsizefrompacket(buffer));
		if (pcount > 10) {
			fflush(outf);
			pcount = 0;
		}
		if (debugmode)
			printf("sending frame: %s for %d\n", buffer, who);
	}
	close(sock1); // close the socket
	close(sock2);

}

double calcFinishTime(double globalTime, double preFi, double Pi) {
	return (double) max(globalTime, preFi) + Pi;
}

int getsizefrompacket(char* buffer) {
	char temp[SIZELENGTH];
	int size;
	strncpy(temp, buffer + IDLENGTH, SIZELENGTH);
	size = atoi(temp);
	while(size>(SIZELENGTH*10))
		size=size/10;
	return size;
}


void *receiver(void *input) {
	RECEIVERSTRUCT* inputstruct;
	char buffer1[FSIZE];
	char buffer2[FSIZE];
	size_t recsize1, recsize2, fromlen;
	int sock1, sock2;
	int uniqueCounter = 0;
	char** mainbuffer1;
	char** mainbuffer2;
	struct sockaddr_in sa1;
	struct sockaddr_in sa2;
	long tempTimestamp;
	double activeflow = 0.0;
	int preHead = 0;
	double tempPi = 0.0;

	inputstruct = (RECEIVERSTRUCT*) input;
	sock1 = inputstruct->socket1;
	sock2 = inputstruct->socket2;
	sa1 = *(inputstruct->saddress1);
	sa2 = *(inputstruct->saddress2);
	mainbuffer1 = inputstruct->mainbuffer1;
	mainbuffer2 = inputstruct->mainbuffer2;

	printf("\n recv ....\n");

	while (1) {
		tempTimestamp = timestamp();
		activeflow = 0.0;

		recsize1 = recvfrom(sock1, (void *) buffer1, FSIZE, 0,
				(struct sockaddr *) &sa1, &fromlen);

		recsize2 = recvfrom(sock2, (void *) buffer2, FSIZE, 0,
				(struct sockaddr *) &sa2, &fromlen);

		if (recsize1 < 0)
			fprintf(stderr, "%s\n", strerror(errno));

		if (flagQ1 && recsize1 > 0) {
			activeflow += WEIGHT1;
			if (flagQ2 && recsize2 > 0)
				activeflow += WEIGHT2;

			globalVirtualTime += (double) (1.0) / activeflow;
			preHead = (head1 - 1) % BSIZEINF;
			if(preHead<0)
				preHead+=BSIZEINF;
			tempPi = (double) getsizefrompacket(buffer1) / WEIGHT1;
			strcpy(mainbuffer1[head1], buffer1);
			finishTime1[head1] = calcFinishTime(globalVirtualTime,
					finishTime1[preHead], tempPi);
			//timeArr1[head1] = tempTimestamp;

			//printf ("Rtime: %ld\n", timestamp());
			if (debugmode) {
				printf("\n recsize1: %d head1: %d ", (int) recsize1, head1);
				printf("datagram: %s\n", buffer1);
			}

			if ((head1 = ((head1 + 1) % BSIZEINF)) == tail1)
				flagQ1 = 0;
		} else {
			if (head1 != tail1)
				flagQ1 = 1;
		}
		//		if (debugmode)
		//			printf("new head1: %d\n", head1);
		//		//end for buffer1


		if (recsize2 < 0)
			fprintf(stderr, "%s\n", strerror(errno));

		if (flagQ2 && recsize2) {
			if (recsize1 < 0) {
				activeflow = WEIGHT2;
				globalVirtualTime += (double) (1.0) / activeflow;
			}
			preHead = (head2 - 1) % BSIZEINF;
			if(preHead<0)
				preHead+=BSIZEINF;
			tempPi = (double) getsizefrompacket(buffer2) / WEIGHT2;
			strcpy(mainbuffer2[head2], buffer2);
			finishTime2[head2] = calcFinishTime(globalVirtualTime,
					finishTime2[preHead], tempPi);
			//timeArr2[head2] = tempTimestamp;
			//add this line
			//finishTime1[head1] = calcFinishTime(); //
			//}
			//printf ("Rtime: %ld\n", timestamp());
			if (debugmode) {
				printf("\n recsize2: %d head1: %d ", (int) recsize2, head2);
				printf("datagram: %s\n", buffer2);
			}
			if ((head2 = ((head2 + 1) % BSIZEINF)) == tail2)
				flagQ2 = 0;
		} else {
			if (head2 != tail2)
				flagQ2 = 1;
		}

		//		if (debugmode)
		//			printf("new head1: %d\n", head2);
		//		//end for buffer2

	}//end of while(1)
}
